using System;
using System.Collections;
using System.Configuration;
using System.Globalization;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using log4net;

namespace X.Ray.Core.Framework
{
    /// <summary>
    /// Author:					Joe Audette
    /// Created:				2004-07-14
    /// Last Modified:			2007-07-08
    /// 
    /// 4/30/2005	Dean Brettle Provided a better handling of proxy settings
    ///				in generating the base path for site links
    /// 02/05/2007  Alexander Yushchenko added TryLoadRequestParam functions
    ///				
    /// The use and distribution terms for this software are covered by the 
    /// Common Public License 1.0 (http://opensource.org/licenses/cpl.php)
    /// which can be found in the file CPL.TXT at the root of this distribution.
    /// By using this software in any fashion, you are agreeing to be bound by 
    /// the terms of this license.
    ///
    /// You must not remove this notice, or any other, from this software.
    /// </summary>
    public static class WebUtils
    {
        private static readonly ILog log = LogManager.GetLogger(typeof(WebUtils));


        public static string GetApplicationRoot()
        {
            if (log.IsDebugEnabled)
                log.Debug("ApplicationPath is " + HttpContext.Current.Request.ApplicationPath);

            if (HttpContext.Current.Request.ApplicationPath.Length == 1)
            {
                return string.Empty;
            }
            else
            {
                return HttpContext.Current.Request.ApplicationPath;
            }
        }

        // Returns hostname[:port] to use when constructing the site root URL.
        private static string getHost(string protocol)
        {
            string serverName = HttpContext.Current.Request.ServerVariables["SERVER_NAME"];
            string serverPort = HttpContext.Current.Request.ServerVariables["SERVER_PORT"];
            if (log.IsDebugEnabled)
            {
                log.Debug("ServerName= " + serverName);
                log.Debug("serverPort= " + serverPort);

            }

            // Most proxies add an X-Forwarded-Host header which contains the original Host header
            // including any non-default port.

            string forwardedHosts = HttpContext.Current.Request.Headers["X-Forwarded-Host"];
            if (forwardedHosts != null)
            {
                // If the request passed thru multiple proxies, they will be separated by commas.
                // We only care about the first one.
                string forwardedHost = forwardedHosts.Split(',')[0];

                if (log.IsDebugEnabled)
                {
                    log.Debug("forwardedHost= " + forwardedHost);

                }

                string[] serverAndPort = forwardedHost.Split(':');
                serverName = serverAndPort[0];

                if (log.IsDebugEnabled)
                {
                    log.Debug("serverName after split from serverAndPort = " + serverName);

                }

                serverPort = null;
                if (serverAndPort.Length > 1)
                {
                    serverPort = serverAndPort[1];
                    if (log.IsDebugEnabled)
                    {
                        log.Debug("serverPort after split from serverAndPort = " + serverPort);

                    }
                }

            }

            // Only include a port if it is not the default for the protocol and MapAlternatePort = true
            // in the config file.
            if ((protocol == "http" && serverPort == "80")
                || (protocol == "https" && serverPort == "443"))
            {
                serverPort = null;
            }

            // added to fix issue reported by user running normal on port 80 but ssl on port 472
            if (protocol == "https" && serverPort == "80")
            {
                if (log.IsDebugEnabled)
                {
                    log.Debug("protocol == https , serverPort == 80");
                }

                bool mapAlternateSSLPort = ConfigHelper.GetBoolProperty("MapAlternateSSLPort", false);
                if (mapAlternateSSLPort)
                {
                    string alternatSSLPort = ConfigurationManager.AppSettings["AlternateSSLPort"];
                    if (alternatSSLPort != null)
                    {
                        serverPort = alternatSSLPort;
                    }
                }

            }

            string host = serverName;

            if (log.IsDebugEnabled)
            {
                log.Debug("host= " + host);

            }


            if (serverPort != null)
            {
                bool mapAlternatePort = ConfigHelper.GetBoolProperty("MapAlternatePort", false);
                if (mapAlternatePort)
                {
                    host += ":" + serverPort;
                }
            }

            return host;
        }

        

        public static string GetSiteRoot()
        {
            string protocol = HttpContext.Current.Request.IsSecureConnection ? "https" : "http";
            string host = getHost(protocol);
            return protocol + "://" + host + GetApplicationRoot();
        }

        public static string GetSecureSiteRoot()
        {
            string protocol = "https";
            string host = getHost(protocol);
            return protocol + "://" + host + GetApplicationRoot();
        }

        public static string GetInSecureSiteRoot()
        {
            string protocol = "http";
            string host = GetHostName();
            return protocol + "://" + host + GetApplicationRoot();
        }

        public static string GetHostName()
        {
            if (HttpContext.Current == null) return String.Empty;

            return HttpContext.Current.Request.ServerVariables["SERVER_NAME"].ToLower();
        }

        public static string GetVirtualRoot()
        {
            string serverName = HttpContext.Current.Request.ServerVariables["SERVER_NAME"];

            return "/" + serverName + GetApplicationRoot();
        }

        public static void ForceSSL()
        {
            bool proxyPreventsSSLDetection;
            bool.TryParse(ConfigurationManager.AppSettings["ProxyPreventsSSLDetection"], out proxyPreventsSSLDetection);
            // proxyPreventsSSLDetection is false if parsing failed for any reason

            if (!proxyPreventsSSLDetection)
            {
                string url = HttpContext.Current.Request.Url.ToString();
                if (url.StartsWith("http:"))
                {
                    HttpContext.Current.Response.Redirect("https" + url.Remove(0, 4), false);
                }
            }
        }

        public static void ClearSSL()
        {
            string url = HttpContext.Current.Request.Url.ToString();
            if (url.StartsWith("https:"))
            {
                HttpContext.Current.Response.Redirect("http" + url.Remove(0, 5), false);
            }
        }

        



        public static string GetQueryString(string rawUrl)
        {
            if (!rawUrl.Contains("?")) return string.Empty;
            if (rawUrl.IndexOf("?") == rawUrl.Length -1) return string.Empty;
            return rawUrl.Substring(rawUrl.IndexOf("?"), rawUrl.Length - rawUrl.IndexOf("?"));

        }

        public static string GetUrlWithoutQueryString(string rawUrl)
        {
            if (!rawUrl.Contains("?")) return rawUrl;
            return rawUrl.Substring(0, rawUrl.IndexOf("?"));

        }



        public static string BuildQueryString(string leaveOutParam)
        {
            if (String.IsNullOrEmpty(leaveOutParam)) return String.Empty;

            string queryString = HttpContext.Current.Request.QueryString.ToString();

            return BuildQueryString(queryString, leaveOutParam);
            
        }

        public static string BuildQueryString(string queryString, string leaveOutParam)
        {
            if (String.IsNullOrEmpty(leaveOutParam)) return String.Empty;
            if (String.IsNullOrEmpty(queryString)) return String.Empty;

            if (queryString.Length > 0)
            {
                if (queryString.StartsWith("?"))
                {
                    queryString = queryString.Remove(0, 1);
                }
                if (!queryString.StartsWith("&"))
                {
                    queryString = "&" + queryString;
                }
                int indexOfLeaveOutParam = queryString.IndexOf("&" + leaveOutParam);
                if (indexOfLeaveOutParam > -1)
                {
                    string leavoutParamValue = HttpContext.Current.Request.Params.Get(leaveOutParam);
                    string stringBeforeLeaveOutParam = queryString.Substring(0, indexOfLeaveOutParam);
                    string stringAfterLeaveOutParam =
                        queryString.Substring(indexOfLeaveOutParam + leaveOutParam.Length + 1 + leavoutParamValue.Length);
                    if (stringAfterLeaveOutParam.Length > 0)
                    {
                        if (!stringAfterLeaveOutParam.StartsWith("&"))
                        {
                            if (stringAfterLeaveOutParam.IndexOf("&") > -1)
                            {
                                stringAfterLeaveOutParam =
                                    stringAfterLeaveOutParam.Substring(stringAfterLeaveOutParam.IndexOf("&"));
                            }
                            else
                            {
                                stringAfterLeaveOutParam = "";
                            }
                        }
                    }
                    queryString = stringBeforeLeaveOutParam + stringAfterLeaveOutParam;
                }
            }
            return queryString;
        }

        public static string RemoveQueryStringParam(string leaveOutParam)
        {
            if (String.IsNullOrEmpty(leaveOutParam)) return String.Empty;

            string queryString = HttpContext.Current.Request.QueryString.ToString();
            return RemoveQueryStringParam(queryString, leaveOutParam);
            
        }

        public static string RemoveQueryStringParam(string queryString, string leaveOutParam)
        {
            if (String.IsNullOrEmpty(leaveOutParam)) return String.Empty;
            if (String.IsNullOrEmpty(queryString)) return String.Empty;
            
            if (queryString.Length > 0)
            {
                if (queryString.StartsWith("?"))
                {
                    queryString = queryString.Remove(0, 1);
                }
                if (!queryString.StartsWith("&"))
                {
                    queryString = "&" + queryString;
                }
                int indexOfLeaveOutParam = queryString.IndexOf("&" + leaveOutParam);
                if (indexOfLeaveOutParam > -1)
                {
                    string stringBeforeLeaveOutParam = queryString.Substring(0, indexOfLeaveOutParam);
                    string stringAfterLeaveOutParam = queryString.Substring(indexOfLeaveOutParam + leaveOutParam.Length);
                    if (stringAfterLeaveOutParam.Length > 0)
                    {
                        if (!stringAfterLeaveOutParam.StartsWith("&"))
                        {
                            if (stringAfterLeaveOutParam.IndexOf("&") > -1)
                            {
                                stringAfterLeaveOutParam =
                                    stringAfterLeaveOutParam.Substring(stringAfterLeaveOutParam.IndexOf("&"));
                            }
                            else
                            {
                                stringAfterLeaveOutParam = "";
                            }
                        }
                    }
                    queryString = stringBeforeLeaveOutParam + stringAfterLeaveOutParam;
                }

                if (queryString.StartsWith("&"))
                {
                    queryString = queryString.Remove(0, 1);
                }
            }
            return queryString;
        }


        //public static string RemoveQueryStringParam(string leaveOutParam)
        //{
        //    if (String.IsNullOrEmpty(leaveOutParam)) return String.Empty;

        //    string queryString = HttpContext.Current.Request.Url.ToString();
        //    queryString = queryString.Remove(0, queryString.IndexOf(".aspx") + 5);
        //    if (queryString.Length > 0)
        //    {
        //        if (queryString.StartsWith("?"))
        //        {
        //            queryString = queryString.Remove(0, 1);
        //        }
        //        if (!queryString.StartsWith("&"))
        //        {
        //            queryString = "&" + queryString;
        //        }
        //        int indexOfLeaveOutParam = queryString.IndexOf("&" + leaveOutParam);
        //        if (indexOfLeaveOutParam > -1)
        //        {
        //            string stringBeforeLeaveOutParam = queryString.Substring(0, indexOfLeaveOutParam);
        //            string stringAfterLeaveOutParam = queryString.Substring(indexOfLeaveOutParam + leaveOutParam.Length);
        //            if (stringAfterLeaveOutParam.Length > 0)
        //            {
        //                if (!stringAfterLeaveOutParam.StartsWith("&"))
        //                {
        //                    if (stringAfterLeaveOutParam.IndexOf("&") > -1)
        //                    {
        //                        stringAfterLeaveOutParam =
        //                            stringAfterLeaveOutParam.Substring(stringAfterLeaveOutParam.IndexOf("&"));
        //                    }
        //                    else
        //                    {
        //                        stringAfterLeaveOutParam = "";
        //                    }
        //                }
        //            }
        //            queryString = stringBeforeLeaveOutParam + stringAfterLeaveOutParam;
        //        }

        //        if (queryString.StartsWith("&"))
        //        {
        //            queryString = queryString.Remove(0, 1);
        //        }
        //    }
        //    return queryString;
        //}

        


        public static void SetupRedirect(Control control, string redirectUrl)
        {
            // the reason for using this overload of Response.Redirect:
            //  Response.Redirect("somepage.aspx", false);
            // as opposed to this
            //  Response.Redirect("somepage.aspx");
            // is that by default true is used which causes Response.End to be invoked automatically
            // this can increase the number of ThreadWasAboutToAbortExceptions and impact performance
            // in some scenarios
            // however using the overlaod with 2 params also allows the current thread to continue processing
            // after redirection which is not neccessarily desireable and can have some security implications.
            // If using redirection to enforce security, like redirecting to the  AccessDenied page, it is best to always
            // use plain old Response.Redirect("somepage.aspx");
            // so that the response is ended immediately.
            // When redirecting after an update maximum performance can be achieved using
            // Response.Redirect("somepage.aspx", false);
            // You should call SiteUtils.UseGracefulThreadEnding after your redirect using
            // Response.Redirect("somepage.aspx", false);
            // in order to gracefully end processing in the most secure fashion possible

            // for more info about the above see
            // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnaspp/html/monitor_perf.asp

            if (redirectUrl != null)
            {
                HttpContext.Current.Response.Redirect(redirectUrl, false);

                if (control != null)
                {
                    control.EnableViewState = false;
                    control.Visible = false;
                }

                HttpContext.Current.ApplicationInstance.CompleteRequest();
                return;
            }

        }


        public static bool NullToFalse(Object o)
        {
            if (o == null) return false;
            if (o is bool) return (bool)o;
            if (o is int) return ((int)o > 0);

            if ((o.ToString().ToLower() == "true") || (o.ToString() == "1")) return true;
            if ((o.ToString().ToLower() == "false") || (o.ToString() == "0")) return false;

            return false;
        }

        public static bool NullToTrue(Object o)
        {
            if (o == null) return true;
            if (o is bool) return (bool)o;
            if (o is int) return ((int)o > 0);

            if ((o.ToString().ToLower() == "true") || (o.ToString() == "1")) return true;
            if ((o.ToString().ToLower() == "false") || (o.ToString() == "0")) return false;

            return true;
        }

        public static Int32 ParseInt32FromHashtable(
            Hashtable settings,
            String key, 
            Int32 defaultIfNotFound)
        {
            int returnValue = defaultIfNotFound;
            
            if (
                (key != null)
                &&(settings.Contains(key))
                && (!Int32.TryParse(
                settings[key].ToString(),
                NumberStyles.Any,
                CultureInfo.InvariantCulture,
                out returnValue))
                )
            {
                returnValue = defaultIfNotFound;
            }
            
            return returnValue;

        }

        public static bool ParseBoolFromHashtable(
            Hashtable settings,
            String key,
            bool defaultIfNotFound)
        {
            bool returnValue = defaultIfNotFound;

            if (
                (settings != null)
                &&(key != null)
                && (settings.Contains(key))
                )
            {
                if (settings[key].ToString().ToLower(CultureInfo.InvariantCulture) == "true")
                {
                    return true;
                }

                return false;
            }

            return returnValue;

        }

        public static Int32 ParseInt32FromQueryString(String ParamName, Int32 DefaultIfNotFoundOrInvalid)
        {
            Int32 paramValue;
            if (TryLoadRequestParam(ParamName, out paramValue)) return paramValue;
            return DefaultIfNotFoundOrInvalid;
        }

        public static DateTime ParseDateFromQueryString(String ParamName, DateTime DefaultIfNotFoundOrInvalid)
        {
            DateTime paramValue;
            if (TryLoadRequestParam(ParamName, out paramValue)) return paramValue;
            return DefaultIfNotFoundOrInvalid;
        }

        public static Guid ParseGuidFromQueryString(String ParamName, Guid DefaultIfNotFoundOrInvalid)
        {
            Guid paramValue;
            if (TryLoadRequestParam(ParamName, out paramValue)) return paramValue;
            return DefaultIfNotFoundOrInvalid;
        }

        /// <summary>
        /// Loads parameter of a given type from query string.
        /// Returns the given value if operation failed.
        /// </summary>
        /// <typeparam name="T">Type of the loaded parameter.</typeparam>
        /// <param name="ParamName">Name of the loaded parameter.</param>
        /// <param name="DefaultIfNotFoundOrInvalid">Value that is returned if operation failed.</param>
        /// <returns>Value of the loaded parameter.</returns>
        public static T LoadOptionalRequestParam<T>(string ParamName, T DefaultIfNotFoundOrInvalid)
        {
            T paramValue;
            if (TryLoadRequestParam(ParamName, out paramValue)) return paramValue;
            return DefaultIfNotFoundOrInvalid;
        }


        #region TryLoadRequestParam functions

        /// <summary>
        /// Loads Int32 parameter from query string.
        /// A return value indicates whether the operation succeeded.
        /// </summary>
        /// <param name="ParamName">Name of the loaded parameter.</param>
        /// <param name="ParamValue">Value of the loaded parameter.</param>
        /// <returns>True if the requested parameter exists in query string and has the right type.</returns>
        public static bool TryLoadRequestParam(String ParamName, out Int32 ParamValue)
        {
            if (String.IsNullOrEmpty(ParamName)) throw new ArgumentNullException("ParamName");
            if (HttpContext.Current == null)
            {
                ParamValue = default(Int32);
                return false;
            }

            return Int32.TryParse(HttpContext.Current.Request.Params[ParamName],
                                  NumberStyles.Integer, CultureInfo.InvariantCulture, out ParamValue);
        }

        /// <summary>
        /// Loads String parameter from query string.
        /// A return value indicates whether the operation succeeded.
        /// </summary>
        /// <param name="ParamName">Name of the loaded parameter.</param>
        /// <param name="ParamValue">Value of the loaded parameter.</param>
        /// <returns>True if the requested parameter exists in query string.</returns>
        public static bool TryLoadRequestParam(String ParamName, out String ParamValue)
        {
            if (String.IsNullOrEmpty(ParamName)) throw new ArgumentNullException("ParamName");
            if (HttpContext.Current == null)
            {
                ParamValue = default(String);
                return false;
            }

            ParamValue = HttpContext.Current.Request.Params[ParamName];
            return (ParamValue != null);
        }

        /// <summary>
        /// Loads DateTime parameter from query string.
        /// A return value indicates whether the operation succeeded.
        /// </summary>
        /// <param name="ParamName">Name of the loaded parameter.</param>
        /// <param name="ParamValue">Value of the loaded parameter.</param>
        /// <returns>True if the requested parameter exists in query string.</returns>
        public static bool TryLoadRequestParam(String ParamName, out DateTime ParamValue)
        {
            if (String.IsNullOrEmpty(ParamName)) throw new ArgumentNullException("ParamName");
            if (HttpContext.Current == null)
            {
                ParamValue = default(DateTime);
                return false;
            }

            return DateTime.TryParse(HttpContext.Current.Request.Params[ParamName],
                                     CultureInfo.InvariantCulture, DateTimeStyles.None, out ParamValue);
        }

        /// <summary>
        /// Loads Guid parameter from query string.
        /// A return value indicates whether the operation succeeded.
        /// </summary>
        /// <param name="ParamName">Name of the loaded parameter.</param>
        /// <param name="ParamValue">Value of the loaded parameter.</param>
        /// <returns>True if the requested parameter exists in query string.</returns>
        public static bool TryLoadRequestParam(String ParamName, out Guid ParamValue)
        {
            if (String.IsNullOrEmpty(ParamName)) throw new ArgumentNullException("ParamName");
            if (HttpContext.Current == null)
            {
                ParamValue = default(Guid);
                return false;
            }

            if (String.IsNullOrEmpty(HttpContext.Current.Request.Params[ParamName]))
            {
                ParamValue = default(Guid);
                return false;
            }

            try
            {
                ParamValue = new Guid(HttpContext.Current.Request.Params[ParamName]);
                return true;
            }
            catch (FormatException)
            {
                ParamValue = default(Guid);
                return false;
            }
        }

        /// <summary>
        /// Loads parameter of a given type from query string.
        /// A return value indicates whether the operation succeeded.
        /// </summary>
        /// <typeparam name="T">Type of the loaded parameter.</typeparam>
        /// <param name="ParamName">Name of the loaded parameter.</param>
        /// <param name="ParamValue">Value of the loaded parameter.</param>
        /// <returns>True if the requested parameter exists in query string and has the right type.</returns>
        public static bool TryLoadRequestParam<T>(string ParamName, out T ParamValue)
        {
            if (String.IsNullOrEmpty(ParamName)) throw new ArgumentNullException("ParamName");
            if (HttpContext.Current == null)
            {
                ParamValue = default(T);
                return false;
            }

            string paramValue = HttpContext.Current.Request.Params[ParamName];
            if (paramValue == null)
            {
                ParamValue = default(T);
                return false;
            }

            try
            {
                ParamValue = (T)Convert.ChangeType(paramValue, typeof(T));
            }
            catch (InvalidCastException)
            {
                ParamValue = default(T);
                return false;
            }

            return true;
        }

        #endregion


        

    }
}
